revert: listen v2 force-end-turn + diarize/word-confidence regen (#89) - #91
Conversation
…reverted knob APIs)
dg-coreylweathers
left a comment
There was a problem hiding this comment.
Approving.
Verified the revert is a clean inverse of 5b6323a — the pre-README-fix tree is byte-identical to the 0.7.1 release commit 8b3c605 — and that 0.7.1's hand patches all survive: the additionalProperties streaming escape hatch, the forward-compat unknown-frame no-op, the fields-less hashCode() set, the ReconnectingWebSocketListener fixes, and the ClientOptions version-marker freeze (plus its release-please generic entry, which is what keeps X-Fern-SDK-Version bumpable with no wire-version drift).
All four review findings actioned:
- B1 — #90 closed, and the body no longer claims release-please will regenerate its own release notes.
- B2 — #93 filed and closed; the body now has a "Forfeited by this revert" section naming all three items and stating plainly that an unreleased fix is forfeited while released behaviour is restored. The
defaultImpl = V2Valuefix is re-applied on all three provider unions in #92, withAgentSettingsProviderDefaultTestrestored.AgentV1UpdateListenShimTestis correctly not restored — it guarded the shim #92 deliberately drops. - S1 —
78c4601restores the accurate retry-behavior prose, keeping only the genuinely-removed tuning knobs out. - S2 — the body now discloses the non-spec scope (Fern toolchain downgrade, freeze-block bookkeeping, README change).
Merge this before #92 — verified git merge-tree is clean in both directions and that the merged tree retains 78c4601's prose.
One heads-up: release-please.yml triggers on push to main, so merging this will open a fresh 0.7.2 release PR whose changelog still advertises the reverted #89 features — 5b6323a remains in range since the v0.7.1 tag and release-please cannot cancel a feat with a revert. Don't merge that release PR; close it as with #90, or park it until #92 lands and hand-delete the 5b6323a Features line before cutting 0.8.0.
…provider + google version (#92) Regenerates the SDK against the latest Fern generator (`4.10.1` → `4.16.0`) and API spec (`ff8fd2b` → `03f0677`), reconciles the hand-maintained patches, and documents the resulting breaking changes with a migration guide. Supersedes the reverted #89. ## Base Stacked on the revert branch (#91). Until that merges, this PR's diff includes the revert commit; merge #91 first (or it rides along). ## ⛔ Blocked / do not merge yet Regenerated from an **unmerged spec branch**: `.fern/metadata.json` `originGitCommit` `03f0677` lives only on `origin/jherlihy/flux-tts-ga`, not on `deepgram-docs` `main`. The launch surface here (`breaks_applied`, `ConfigureFailure`, `expressivity`, `speed`, `redact`) exists only on that branch. Kept as a **draft** until it lands. - **Blocked-on:** `deepgram-docs#1094` (Flux TTS copy) + the `jherlihy/flux-tts-ga` spec branch merging to `deepgram-docs` `main`. ## Breaking changes (pre-1.0, source/compile-time only) All three follow the API definition; on-the-wire payloads for existing requests are unchanged. Full before/after in [`docs/Migrating-v0.7-to-v0.8.md`](./docs/Migrating-v0.7-to-v0.8.md). 1. **`AgentV1UpdateListenListen.provider`** retyped `DeepgramListenProviderV2` → `AgentV1UpdateListenListenProvider` (V1/V2 union). Wrap with `AgentV1UpdateListenListenProvider.v2(...)`; read via `getV2()`. 2. **`Google.version`** retyped `Optional<String>` → `Optional<GoogleThinkProviderVersion>`. Use the enum constants (`V1BETA`, `AI_STUDIO_V1BETA`, `GEMINI_ENTERPRISE_AGENT_V1`). 3. **`SpeakV2SpeechMetadataControlsApplied`** gains a required `breaksApplied` field (new builder step; new `getBreaksApplied()`). Read paths unaffected. Origin verified: #2 and #3 are new in the latest spec; #1's union shape existed in #89 but was previously hidden behind an in-SDK shim we intentionally did not carry forward. ## Reconciliation (post-regen review) Diffed each of the 17 `.bak` patches against the freshly generated originals — **all 17 still needed**, none dropped. `.fernignore` restored to its pre-prep state; all `.bak` files deleted. - **13 restored verbatim** (generator produced no other changes): the 11 fields-less `hashCode()` types, `ReconnectingWebSocketListener` (override hook / `connectionTimeoutMs` / `maxRetries(0)` semantics), and the `listen/v1` + `speak/v1` websocket clients (query-param repeats + `additionalProperties`). - **2 surgically merged** (`listen/v2` + `speak/v2` websocket clients): re-applied `QueryStringMapper` array-param serialization, the `additionalProperties` escape hatch, and the forward-compat unknown-message no-op, **while keeping the generator's new features** (speak/v2 `sendInterrupt`/`sendConfigure` + `onSpeechInterrupted`/`onConfigureSuccess`/`onConfigureFailure`; listen/v2 `redact`). - **`ClientOptions`**: kept the new retry-tuning options + `ResponseDecompressionInterceptor`; re-applied only the two `// x-release-please-version` header lines (colon SDK-name form), removed the generator's `getSdkVersion()` helper (build does not stamp the JAR manifest, so it would drift). ## Additive highlights Speak V2 interrupt/configure, Listen V2 `redact`, Speak V2 `speed`/`expressivity`, new Deepgram Flux TTS voices, client retry tuning, automatic response decompression. ## Tests added - `ListenV2ConnectWireTest`: new `redact` connect param (present as wire `numbers`, omitted when absent). - `RegenTypesTest` → "2026-08-11 regen type shapes": the three breaking shapes (provider union v2 factory/`getV2`/serialization, `Google.version` enum wire value, `ListenV2Redact` wire values). ## Verification - `./gradlew unitTest` ✅ · `spotlessCheck` ✅ · `compileExamples` ✅ - `./gradlew integrationTest` ✅ (Tier 1 + Tier 2 against a live key); opt-in Speak V2 WS integration ✅ (returned audio over the new v2 WS path) - Ran all non-`manage` examples: 19 pass, 7 long-running streaming/agent examples connected and worked, 4 environmental (proxy / file-arg / callback URL / SageMaker) — no SDK regressions. ## Post-review additions (from #91 review) - **Re-applied the union default-variant fix** the #89 revert forfeited (issue #93): `defaultImpl = V2Value` on `AgentV1UpdateListenListenProvider`, `AgentV1SettingsAgentListenProvider`, `AgentV1SettingsAgentContextListenProvider`, so a provider payload omitting the optional `version` discriminator (what 0.7.x emits) deserializes as V2 instead of dropping to `{"provider":null}`. Frozen in `.fernignore` + `AGENTS.md`, guarded by the re-added `AgentSettingsProviderDefaultTest`. The `getProvider()` return-type shim is intentionally **not** re-applied — that retype is a deliberate breaking change (see the migration guide). ## Core behavior changes (generator 4.10.1 → 4.16.0) Beyond the spec features, the generator upgrade changes core HTTP-client behavior worth calling out in the release notes: - **Automatic response decompression** is now installed by default (`ResponseDecompressionInterceptor`): gzip/deflate-encoded HTTP responses are transparently decoded. No API change; transparent to callers. - **New optional retry tuning** on `ClientOptions.Builder`: `initialRetryDelayMillis`, `maxRetryDelayMillis`, `retryJitterFactor`. All defaulted — existing behavior is unchanged unless set. ## Follow-ups - Once this lands, release-please cuts a fresh release at **0.8.0** (breaking `feat!`). - **Changelog needs a manual edit before releasing.** `5b6323a` (#89 `feat(regen)`) is still in release-please's range since `v0.7.1`, and release-please can't pair a revert with the commit it reverts — so the generated 0.8.0 notes will re-list the reverted #89 features (`diarize_info`, force-end-turn) under Features. Hand-edit the release PR's `CHANGELOG.md` to drop them before merging it. BREAKING CHANGE: `AgentV1UpdateListenListen.provider` is now `AgentV1UpdateListenListenProvider` (V1/V2 union); `Google.version` is now `Optional<GoogleThinkProviderVersion>`; `SpeakV2SpeechMetadataControlsApplied` has a new required `breaksApplied` field. See docs/Migrating-v0.7-to-v0.8.md. --------- Co-authored-by: fern-api[bot] <115122769+fern-api[bot]@users.noreply.github.com>
…nale Two gaps in the preceding regen-reconciliation commit. 1. ListenV2ForceEndTurn was generated unpatched. It is a 12th fields-less message type with equals() and no hashCode(), so it violated the Object contract like the other 11. Diffing .bak files could not catch it: the type is newly generated (reverted out in #91, reintroduced by 4.18.0), so it had no .bak to compare against. Added the hashCode() patch, froze it in .fernignore, listed it in AGENTS.md, and extended RegenTypesTest.FieldsLessMessageContract to assert it. Added a post-regen sweep step to AGENTS.md so a newly generated fields-less type cannot slip through this way again. 2. The ClientOptions rationale in the previous commit message and the PR body was wrong on a point of fact. It claimed 4.18.0's getSdkVersion() helper "always resolves null" because build.gradle sets no jar manifest attributes. That is only true for Gradle builds and tests. The published artifact is built by Maven (release-please.yml runs `mvn deploy -P release`) and pom.xml's maven-jar-plugin sets addDefaultImplementationEntries=true, so the published JAR manifest does carry Implementation-Version and the generator's helper would resolve correctly there. The decision to keep the explicit literals still stands, on the accurate rationale: they are correct under Gradle, Maven, and tests alike, whereas getSdkVersion() is correct only via Maven and silently reports a stale generator-authored fallback everywhere else. release-please already lists this file in extra-files, so the markers are actively wired. Recorded in AGENTS.md. Verified: ./gradlew test compileExamples -> 112 tests, 0 failures, 1 skipped.
…vider/agent-history types (#96) Fern SDK regeneration for 2026-08-19 (`fern-java-sdk` **4.16.0 → 4.18.0**, CLI 5.44.6 → 5.95.1, spec `03f0677` → `068de88`). **Status:** reconciled & verified. All 8 CI checks green — Spotless, Compile (Java 11/17/21), Unit Tests (Java 11/17/21), Title Check. Locally `./gradlew spotlessCheck test compileExamples` → **123 passed / 1 skipped** (the skip is the opt-in `SpeakV2WebSocket` test; with `DEEPGRAM_SPEAK_V2_WS=1` it passes, making `integrationTest` 7/7). Ships **2 breaking source changes**, both documented in [`docs/Migrating-v0.8-to-v0.9.md`](./docs/Migrating-v0.8-to-v0.9.md). Both are source-level renames with identical wire values, so no request payload changes and a clean recompile is the whole migration. ## New in this regen - **Listen V2 force-end-turn** — `sendForceEndTurn()` + `ListenV2ForceEndTurn`, plus `ListenV2TurnInfo.getTrigger()` (`Optional<String>`, open-typed) identifying what ended a turn. **Now enabled on staging and verified end-to-end; still gated on production — see [Force-end-turn: verified on staging, gated on production](#force-end-turn-verified-on-staging-gated-on-production).** - **Listen V1 diarization detail** — `getDiarizeInfo()` on the response/results metadata (`getModelUuid()`, `getArch()`) identifying which diarizer ran, plus per-word `getSpeakerConfidence()` (`Optional<Float>`) on pre-recorded words items. `speaker_confidence` is pre-recorded only, not streaming. - **25 new `DeepgramModel` constants**, including the Flux TTS voices. - **Provider/agent-history type renames** — the generator dropped the `*ThinkProvider*` / `*SpeakProvider*` prefixes and consolidated the agent conversation-history leaf types. ## Force-end-turn: verified on staging, gated on production **Updated 2026-08-20 — this supersedes the earlier "cannot be tested end-to-end" finding.** The gate has since opened on staging, so the feature is now verified against a live server through the SDK's own `V2WebSocketClient` (not a raw socket): stream real audio, force the turn to end mid-sentence, read back `trigger`. | Probe | `api.staging.deepgram.com` | `api.deepgram.com` | |---|---|---| | Baseline connect + stream audio | Connected, `TurnInfo` flowing | Connected, `TurnInfo` flowing | | `{"type":"ForceEndTurn"}` | **Accepted** — no error, socket stays open | `UNPARSABLE_CLIENT_MESSAGE` — *"The ForceEndTurn message is not enabled on this deployment."*, socket closed | | `EndOfTurn` after the force | `trigger=manual`, `end_of_turn_confidence=0.0081` | never reached — socket closed first | | Natural `EndOfTurn` (no force) | `trigger=model`, `end_of_turn_confidence=0.773` | `trigger` absent | Two details confirm the feature genuinely works rather than the turn coincidentally ending: - **`end_of_turn_confidence=0.0081` on the forced turn.** The model was nowhere near ending it — compare `0.773` at a natural end. The turn ended because we asked. - **The stream survives and advances.** After the forced end the turn index incremented, `StartOfTurn` fired again, and transcription continued. That is the intended semantic, not a disconnect. **No SDK change was needed.** `sendForceEndTurn()` serialized correctly and `getTrigger()` deserialized both `manual` and `model` unmodified. Typing `trigger` as an open `Optional<String>` rather than a closed enum is what made that hold. ### Correcting the earlier evidence The previous revision argued the gate was closed everywhere partly because *"`trigger` came back absent on every `TurnInfo`."* That was weaker than it read: `trigger` is documented as present on `EndOfTurn` **and only there**, and any probe that sends `ForceEndTurn` to a gated deployment gets its socket closed before reaching an `EndOfTurn` — so the observation was equally consistent with `trigger` working fine. The bottom row above closes that hole by streaming through to a *natural* `EndOfTurn`: on production `trigger` is still absent there, which is the claim that actually needed support. **Caveat, unchanged:** one API key per environment, so this shows the gate is open *for that staging project*. Whether enablement is per-project, per-deployment, or global still needs someone with the feature-flag config. This is also why #91 reverted force-end-turn previously. The difference now is that the typed surface ships with an accurate enablement warning — and, on a deployment that has it, live coverage. ## Breaking changes (documented, not shimmed) Java has no type aliases, so there is no way to keep the old names as exact aliases of the new ones. A deprecated constants-only shim class would fix inline call sites like `.model(DeepgramSpeakProviderModel.AURA2ASTERIA_EN)`, but it cannot preserve a **return type** — and `Optional<GoogleThinkProviderVersion> v = google.getVersion()` is the exact line 0.8.0's own migration guide told users to write. Binary compatibility is broken regardless, so every consumer recompiles. This repo has no `@Deprecated` anywhere and shipped 0.8.0 as `feat(regen)!` with a migration guide; this cycle follows that convention. **9 renames** (constant names and wire values unchanged): | v0.8.x | v0.9.0 | | --- | --- | | `AnthropicThinkProviderModel` | `AnthropicModel` | | `CartesiaSpeakProviderModelId` | `CartesiaModelId` | | `CartesiaSpeakProviderVoice` | `CartesiaVoice` | | `DeepgramSpeakProviderModel` | `DeepgramModel` | | `GoogleThinkProviderModel` | `GoogleModel` | | `GoogleThinkProviderVersion` | `GoogleVersion` | | `GroqThinkProviderReasoningMode` | `GroqReasoningMode` | | `AgentV1HistoryContentRole` | `ConversationHistoryMessageRole` | | `AgentV1HistoryFunctionCallsFunctionCallsItem` | `FunctionCallHistoryMessageFunctionCallsItem` | `OpenAiThinkProvider*` is not renamed (it collides, so the generator keeps the long form). **2 duplicate types removed** — `AgentV1SettingsAgentContextContextMessagesItemContentRole` and `...FunctionCallsFunctionCallsItem` are replaced by the canonical `ConversationHistoryMessageRole` / `FunctionCallHistoryMessageFunctionCallsItem`. Verified structurally identical: same constants, same `"user"`/`"assistant"` wire values. **The ripple is wider than the type list implies.** A `javap` surface diff over all 1688 public types at 0.8.0 vs HEAD found **53 removed public types** and **30 removed public members across 21 surviving types** — because seven carrier types changed both getter return types and builder parameter types: `Anthropic`, `Cartesia`, `Deepgram`, `Google`, `Groq`, `ConversationHistoryMessage`, `FunctionCallHistoryMessage`. The migration guide lists each with its affected members. **Every removal traces to those 11 renamed/deleted types — zero unexplained removals, and no new required builder stages**, so there is no 0.8.0-style "gained a required field" break hiding in here. ## Two generator regressions patched, not shipped ### `speak.v2` connect `speed` The generator retyped `V2ConnectOptions.speed` from `Optional<Double>` to a closed 7-value string-literal enum. **Not shipped** — restored to `Double` and frozen, so existing `.speed(1.05)` callers are unaffected. The generated type contradicts the API contract two ways: the mid-stream `SpeakV2Configure.speed` on the same connection is still `Optional<Double>`, and the server parses the numeric form and range-checks it (`SPEED_OUT_OF_RANGE` outside `0.85`–`1.15`, `SPEED_INCREMENT_INVALID` off the `0.05` increment) — so a closed enum cannot express a valid in-range value it omits. Guarded by `SpeakV2ConnectWireTest`; the generated `SpeakV2Speed` type is left in place, unused, as documentation of the accepted values, and it appears in no public signature. Unfreeze when the spec types the connect `speed` as a number. ### `DeepgramModel.FLUX_RENEE_EN` The generator removed this constant. **Not shipped** — restored and frozen. Verified against the live API rather than assumed: - `POST /v2/speak?model=flux-renee-en` → **200** with a valid 3.1s MP3 (MPEG layer III, 48 kbps, 24 kHz mono — Flux TTS's output format). - The name resolves in the server's model **registry, not by prefix**: an invented `flux-bogus-nonexistent-en` is rejected with `INVALID_QUERY_PARAMETER`, while `flux-renee-en` is accepted. - It also appears in a July 2026 internal regression sweep across all speakers and in current voice rosters, with no deprecation or sunset language. So the removal is a spec regression, not a retirement. All five touchpoints restored (constant, `Value` enum, `visit()` case, `valueOf()` case, `Visitor` method); guarded by a `RegenTypesTest` case asserting the wire value, `valueOf()` resolution, and JSON round-trip. **The 25 additions are all retained — the enum now has 100 constants, with nothing removed relative to 0.8.0.**⚠️ Freezing `DeepgramModel` carries a risk the other frozen files don't: it receives frequent additive spec changes, so restoring its `.bak` wholesale on a future regen would silently drop new voices. `.fernignore` and `AGENTS.md` both carry an explicit warning to diff and carry additions forward instead. ## Patch reconciliation **4.18.0 fixed none of the five existing defect groups.** All 20 frozen files re-patched, all 20 `.fernignore` paths restored; 3 files newly frozen (`V2ConnectOptions`, `ListenV2ForceEndTurn`, `DeepgramModel`). Every `.bak` deleted. | Patch group | Files | Evidence in 4.18.0 output | |---|---|---| | Fields-less `hashCode()` | 11 → **12** | Still emits `equals()` with no `hashCode()` | | Union `defaultImpl` | 3 | Still `defaultImpl = _UnknownValue.class` | | WS array query-params | 3 | Still `addQueryParameter("keyterm", String.valueOf(...))` | | WS `additionalProperties` | 4 | `connect()` still never emits them | | Forward-compat no-op | 2 | Unknown frames still routed to `onError` | | `ReconnectingWebSocketListener` | 1 | `retryCount >= maxRetries`, hardcoded `4000`, no `applyOptionsOverride` | **`ListenV2ForceEndTurn` reached the branch unpatched.** It is a 12th fields-less type with `equals()` and no `hashCode()`. Diffing `.bak` files structurally cannot catch this — the type was reverted out in #91 and reintroduced by 4.18.0, so it was newly generated with no `.bak` to compare against. Now patched, frozen, and asserted by `RegenTypesTest`. A post-regen sweep step was added to `AGENTS.md` so this class of miss cannot recur. **`applyOptionsOverride` is load-bearing.** `core/transport/TransportWebSocketFactory.java:39` calls it and is permanently frozen, so main source does not compile without the patch. **`ClientOptions` stays frozen.** 4.18.0 replaced the version literals with `getSdkVersion()` reading `Package.getImplementationVersion()`. That *does* resolve in the published artifact (CI runs `mvn deploy -P release`; `pom.xml`'s maven-jar-plugin sets `addDefaultImplementationEntries=true`), but resolves to `null` under Gradle and in tests, falling back to a generator-authored literal nothing keeps current. `.github/release-please-config.json` already lists this file in `extra-files`, so the `// x-release-please-version` markers are actively wired. Also keeps `User-Agent` on the `com.deepgram:` coordinate form to match `X-Fern-SDK-Name`. **`AGENTS.md` validation command corrected** to `./gradlew spotlessCheck test compileExamples`. CI runs Spotless as its own job, so the previously documented `test compileExamples` passed locally while CI failed — which happened on this branch. Hand-re-applying patches trips the formatter routinely, since inserted comments and renamed types change how chained calls wrap. ## Verification - **CI:** all 8 checks green. - **Unit:** `unitTest` → 106 passed, 0 skipped. Every patch group's regression guard passes: `applyOptionsOverride` (2), `maxRetries(0)` (1), `ReconnectOptions builder` (4), fields-less `hashCode()` (1), `FLUX_RENEE_EN` (1), `AgentSettingsProviderDefaultTest` (3), both forward-compat tests, and the wire tests (`ListenV1` 7, `ListenV2` 9, `SpeakV2` 7, `StreamingAdditionalProperties` 4, `QueryStringMapper` 12). - **Integration (live API):** `integrationTest` → **8/8** with `DEEPGRAM_SPEAK_V2_WS=1` and `DEEPGRAM_LISTEN_V2_FORCE_END_TURN=1` against staging; 6/8 with 2 skips against production, where both gated features are unavailable. There is no separate e2e suite — the live-API integration tests plus the examples are that layer. - **Examples:** all 32 non-`manage` examples run (31 previously, plus the new `listen/ForceEndTurn`). 20 exit clean; 7 time out and 4 fail, and **every one of those 11 reproduces identically on a 0.8.0 worktree**, so there are no example regressions. The failures are environmental (no local proxy, a missing CLI argument, a missing audio file, a placeholder callback URL) and the timeouts are streaming examples that finish their work but leave a non-daemon executor holding the JVM open, plus three agent examples hitting server-side `CLIENT_MESSAGE_TIMEOUT` / `INVALID_SETTINGS`. All pre-existing. - **Rename safety:** across all six renamed enums, **0 wire values changed and 0 constants lost** — the renames are purely nominal. - **API surface:** `javap` diff vs 0.8.0 confirms the breaking scope is bounded to the renames. - **Live API:** `flux-renee-en` confirmed serving; force-end-turn confirmed working on staging (`trigger=manual`) and still gated on production. ### Version bump Title is `feat(regen)!` so release-please computes a minor bump to `0.9.0` from the squash-merge message. The `!` matters — the migration guide is written for `0.8` → `0.9`. ## Test coverage added The new surface from this regen arrived untested; that is now closed. - **`ListenV2ControlFrameWireTest`** (new) — `sendForceEndTurn` had no test at all. Asserts the frame arrives, that it carries nothing but the discriminator (exact match, since the server rejects unknown fields on control messages), and `sendCloseStream` as a control so a future failure separates "send path broke" from "ForceEndTurn broke". This runs on every build regardless of deployment gating, so it stays the baseline guard wherever the live test skips. - **`RegenTypesTest.Regen20260819`** (new) — 7 cases over `ListenV2TurnInfo.trigger`, both `DiarizeInfo` variants, and words-item `speaker_confidence`, parsed from realistic server payloads rather than builder round-trips. Each is also asserted **absent**, since absence is normal: `trigger` appears only on `EndOfTurn`, `diarize_info` only with diarization on, and `speaker_confidence` is pre-recorded only. The `trigger=manual` fixture matches what the live server returns verbatim. - **`IntegrationTest.testIntegration_ListenV2ForceEndTurn`** (new) — the first live-API coverage of the listen v2 WebSocket in this repo, which previously had none at all. Streams real audio, waits for `StartOfTurn` so there is a turn to end, forces it, and asserts `trigger=manual` with no server error. Opt-in via `DEEPGRAM_LISTEN_V2_FORCE_END_TURN=1`, so it skips cleanly where the feature is gated rather than failing the build — same pattern as the existing `DEEPGRAM_SPEAK_V2_WS` test. Verified passing against staging and skipping against production. - **`examples/listen/ForceEndTurn.java`** (new) — no example used `sendForceEndTurn`, and `LiveStreamingV2` never actually streams audio, so no example reached a `TurnInfo` at all. This one streams real audio, forces a turn end, and prints the `trigger`. On a gated deployment it reports that and exits cleanly rather than crashing. Verified against both. - **`IntegrationTest`** — the `SpeakV2WebSocket` test now sets `speed(1.05)`, so the `speed` patch is exercised against a real server rather than only a mock. Verified passing live. ## ⚠ Merging: the squash message needs a `BREAKING CHANGE:` footer **This is required, not optional.** release-please builds the `### ⚠ BREAKING CHANGES` section of `CHANGELOG.md` from a literal `BREAKING CHANGE:` footer in the squash-merge commit body — that is how 0.8.0's entry got its text. **No commit on this branch has one**, and the `!` in the title alone only triggers the version bump; it does not produce the explanatory text or the migration-guide link. Merging with GitHub's default (this whole review document as the commit body) would ship 0.9.0 with an unexplained breaking-changes section. Use this as the squash-merge message instead: ``` feat(regen)!: listen v2 force-end-turn + diarize metadata; rename provider/agent-history types Regenerates against Fern generator 4.16.0 -> 4.18.0 (CLI 5.44.6 -> 5.95.1, spec 03f0677 -> 068de88), re-applies the hand-maintained patches, and documents the resulting breaking changes with a migration guide. Features: - Listen v2 force-end-turn: sendForceEndTurn() + ListenV2ForceEndTurn, plus ListenV2TurnInfo.getTrigger() identifying what ended a turn. Requires server-side enablement and is rejected on staging and production today, so the typed surface ships but must not be depended on yet. - Listen v1 diarization detail: getDiarizeInfo() (model_uuid, arch) on the response and results metadata, plus per-word getSpeakerConfidence() on pre-recorded words items. - 25 new DeepgramModel voice constants, including the Flux TTS voices. Two generator regressions are patched rather than shipped: the speak v2 connect `speed` param stays Optional<Double> (the generator retyped it to a closed string enum, contradicting the numeric API contract), and DeepgramModel.FLUX_RENEE_EN is restored (the voice is live and serving; the removal was a spec regression). BREAKING CHANGE: the provider and agent-history types lost their role prefixes — `AnthropicThinkProviderModel` → `AnthropicModel`, `CartesiaSpeakProviderModelId` → `CartesiaModelId`, `CartesiaSpeakProviderVoice` → `CartesiaVoice`, `DeepgramSpeakProviderModel` → `DeepgramModel`, `GoogleThinkProviderModel` → `GoogleModel`, `GoogleThinkProviderVersion` → `GoogleVersion`, `GroqThinkProviderReasoningMode` → `GroqReasoningMode`, `AgentV1HistoryContentRole` → `ConversationHistoryMessageRole`, `AgentV1HistoryFunctionCallsFunctionCallsItem` → `FunctionCallHistoryMessageFunctionCallsItem`. The duplicate `AgentV1SettingsAgentContextContextMessagesItemContentRole` and `...FunctionCallsFunctionCallsItem` are removed in favour of the canonical types. Getter return types and builder parameters on `Anthropic`, `Cartesia`, `Deepgram`, `Google`, `Groq`, `ConversationHistoryMessage` and `FunctionCallHistoryMessage` change accordingly. All wire values are unchanged, so no request payloads change. See docs/Migrating-v0.8-to-v0.9.md. ``` Unlike 0.8.0, the release-please range is clean — `v0.8.0..main` is empty, so this squash commit will be its only input and there is no reverted-commit pairing to hand-edit out of the release PR this time. ## Follow-ups - Two spec-side regressions are patched but not yet filed upstream: the `speed` retype and the dropped `FLUX_RENEE_EN` constant. That is two items on top of the six existing open Fern requests, none of which 4.18.0 addressed. - Force-end-turn is verified on staging but still gated on production. Re-run `integrationTest` with `DEEPGRAM_LISTEN_V2_FORCE_END_TURN=1` against production once the gate lifts there; the test is written to need no changes when it does, and the `trigger` wording in the migration guide can drop its enablement caveat at that point. --------- Co-authored-by: fern-api[bot] <115122769+fern-api[bot]@users.noreply.github.com>
Reverts the listen v2 regen (
5b6323a, originally #89: Flux force-end-turn, listen v1 diarize metadata + arch, word speaker confidence,AgentV1UpdateListenprovider retype,ListenV2Redact) offmain.Mirrors the equivalent revert on deepgram-python-sdk: deepgram/deepgram-python-sdk#757
Why
This work isn't ready to ship yet, and other priorities need to release from
mainwithout it. Since the regen is already onmain, any release cut frommain(including the pending release-please 0.7.2, #90) would publish it. Reverting removes it from the release line cleanly, without rewriting history.Redoing the regen
The regen commit
5b6323astays reachable in history (and on the #89 branch), and the next regen branchgh/sdk-gen-2026-08-11(#92) is stacked on this revert. Caveat: re-landing is a fresh 4.16.0 regen, not a replay of #89's hand-patches — see "Forfeited by this revert" below.Also reverted (not spec features)
Beyond the five spec features, this 184-file revert also rolls back:
.fern/metadata.json):cliVersion5.89.0 → 5.44.6,generatorVersion4.16.0 → 4.10.1,runtime-versiondropped. This is what makes most of the rest follow.ClientOptions.java.fernignorefreeze block + its release-pleasegenericextra-file entry (both dropped by feat(regen): add diarize_info, Flux force-end-turn, update-listen, word speaker confidence #89) — this is what keepsX-Fern-SDK-Versionrelease-please-bumpable (no wire-version drift).ListenV2ForceEndTurnhashCode()entry from.fernignoreandAGENTS.md.README.md: removes the 4.16.0 retry-knob docs (retry-behavior prose that remains accurate has been restored — see the diff).Forfeited by this revert (tracked in #93)
The revert also drops patches #89 carried that are not preserved on
gh/sdk-gen-2026-08-11and not among #92's 17 reconciled patches (verified: all three unions readdefaultImpl = _UnknownValue.classon #92, both tests absent):defaultImpl = V2Value) onAgentV1UpdateListenListenProvider,AgentV1SettingsAgentListenProvider,AgentV1SettingsAgentContextListenProvider. The two Settings unions carry this bug in released 0.7.1 (pre-existing, not a regression), so the revert restores released behavior — it forfeits an unreleased fix.AgentV1UpdateListenListen.getProvider()additive return-type shim.AgentV1UpdateListenShimTest.java,AgentSettingsProviderDefaultTest.java.Whether to re-apply the
defaultImplfix on #92 is a deliberate decision tracked in #93.Verification
./gradlew compileJava compileExamples unitTest— build successful, all unit tests pass.git diff 5b6323a^ HEADover the pre-README-fix tree is empty (byte-identical to the 0.7.1 release commit8b3c605). Restores pre-regen.fern/metadata.json(sdkVersion 0.7.1, generator 4.10.1), the.fernignorefreeze blocks, and therelease-please-config.jsonClientOptions.javageneric entry.additionalProperties), forward-compat no-op, and fields-lesshashCode()patches from 0.7.1 all survive.